package io.jsen.meta.diff.field;

import com.google.common.reflect.TypeToken;
import io.jsen.meta.diff.annotation.parser.CoAnnotation;
import io.jsen.meta.diff.annotation.parser.MetaFieldDefineSupport;
import io.jsen.meta.diff.exception.MetaReflectionException;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

/**
 * 字段的定义由
 * class + fieldName 组成
 * <p>
 * 如果fieldName为空代表是clazz
 *
 * @author jsen
 * @date 2021/4/7
 */
@Data
@SuppressWarnings("all")
public class MetaFieldDefine {

    private TypeToken typeToken;
    private Field field;

    private List<Class<?>> genericTypeList;


    public MetaFieldDefine(TypeToken typeToken, List<Class<?>> genericTypeList) {
        this.typeToken = typeToken;
        this.genericTypeList = genericTypeList;
        field = null;
    }

    public MetaFieldDefine(TypeToken typeToken, Field field, List<Class<?>> genericTypeList) {
        this.typeToken = typeToken;
        this.field = field;
        this.genericTypeList = genericTypeList;
    }

    public Object getValue(Object obj) {
        try {
            String fieldName = field.getName();
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = "get" + firstLetter + fieldName.substring(1);
            Method method = obj.getClass().getMethod(getter);
            return method.invoke(obj);
        } catch (Exception e) {
            throw new MetaReflectionException("获取字段失败", e);
        }
    }

    public void setValue(Object obj, Object val) {
        try {
            String fieldName = field.getName();
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String methodName = "set" + firstLetter + fieldName.substring(1);
            Method set = getTargetClass().getMethod(methodName, getField().getType());
            set.invoke(obj, val);
        } catch (Exception e) {
            throw new MetaReflectionException("获取字段失败", e);
        }
    }

    public Class<?> getTargetClass() {
        return typeToken.getRawType();
    }

    public Class<?> getCurrentFieldClass() {
        if (field == null) {
            return typeToken.getRawType();
        }
        return field.getType();
    }

    /**
     * 获取字段类型为主typeToken的MetaFieldDefine
     *
     * @return MetaFieldDefine
     */
    public TypeToken<?> getCurrentFieldTypeToken() {
        if (field == null) {
            return typeToken;
        }
        return TypeToken.of(field.getType());
    }

    @Override
    public String toString() {
        CoAnnotation annotation = MetaFieldDefineSupport
                .getMetaFieldAnnotation(this);
        if (annotation != null && StringUtils.isNotBlank(annotation.getAlias())) {
            return annotation.getAlias();
        }
        if (field != null) {
            return field.getName();
        }
        return getTargetClass().getSimpleName();
    }

    public boolean getIgnore() {
        CoAnnotation annotation = MetaFieldDefineSupport
                .getMetaFieldAnnotation(this);
        if (annotation == null) {
            return false;
        }
        return annotation.isIgnore();
    }

    private String getClassName() {
        return typeToken.getRawType().getName();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MetaFieldDefine that = (MetaFieldDefine) o;
        return typeToken.equals(that.typeToken) && Objects.equals(field, that.field);
    }

    @Override
    public int hashCode() {
        return Objects.hash(typeToken, field);
    }
}
